﻿#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
//操作符：
	//一、操作符的分类：
	//算数操作符、移位操作符、位操作符、赋值操作符、单目操作符、关系操作符、逻辑操作符
	//条件操作符、逗号表达式、下标引用、函数调用和结构成员
	
int main()
{
	//1.算数操作符（+、-、*、/、%）
	
	//例如：除号操作符（运算符）
	int ret = 10 / 3;//注：对于除法操作符，两边的数都是整数，执行的是整数除法
	//如果像计算出小数，则符号两点至少有一个数是浮点数
	//例如：
	double tmp = 10.0 / 3;
	printf("%d\n", ret);
	printf("%lf\n", tmp);
	//如果想保证打印多少位，直接写成%.多少位lf
	//例如，打印一位：
	printf("%.1lf\n", tmp);

	//例如：取余操作符
	int a = 10 % 3;//取模（取余数，计算的是整出之后的余数）
	printf("%d\n", a);
	//注：取模操作符的两边必须是整数，返回的也是整数
	return 0;
}

int main()
{
	//2.移位操作符
	//  << 左移操作符
	//  >> 右移操作符
	// 注：移位操作符移位的操作数只能是整数
	// 内存中存储的是反码，所以在移位的时候，一定是移动的补码
	// //补码得到原码也可以进行符号位不变，其他位按位取反，在＋1
	//移位：移的是2进制位
	// 1）<< 左移操作符
	//正数：
	int a = 10;//00000000000000000000000000001010 - 补码
	int b = a << 1;
	//左移就是整体向左移动，超出的舍弃，末尾不分补0(左边丢弃，右边补0)
	//a << 1的结果是移位之后的效果，但是a是不变的
	printf("%d\n", b);// 20

	//负数
	int c = -10;//11111111111111111111111111110110 - 补码
	int d = c << 1;
	//左移就是整体向左移动，超出的舍弃，末尾不分补0(左边丢弃，右边补0)
	//补码移动后要计算回原码
	printf("%d\n", d);// -20

	// 2）<< 右移操作符（两种右移取决于编译器）
	//1.算数右移（常见）
	// 右边丢弃，左边补原来的符号位
	
	//2.逻辑右移
	//右边丢弃，左边直接补零

	int e = -1;
	int f = e >> 1;
	printf("%d\n", f);//算数右移，结果是-1

	//注意：移位的时候是不能移动负数的
	return 0;
}

int main()
{
	//3.位操作符
	//常见的有以下：
	
	// 1） & 按位与：对二进制位对应的进行与运算，同时为1则为1，其他都为0
	int a = 3;
	int b = -5;
	int c = a & b;
	//对a和b的补码进行按位与计算
	printf("%d\n", c);

	//  2） | 按位或:有1就为1，两个同时为0才为0，同样是对二进制的运算
	int d = a | b;
	printf("%d\n", d);//按位或，结果是-5

	// 3）  ^  按位异或 :相同为0，不同为1
	int e = a ^ b;
	printf("%d\n", e);
	 
	//以上三个操作符针对的都是整数，并且都是针对二进制位的
	return 0;
}


//一道变态的面试题：
//不能创建临时变量（第三个变量），实现两个数的交换，以下程序就可以实现：

//方法一：(异或运算）
int main()
{
	int a = 10;
	int b = 20;

	a = a ^ b;
	b = a ^ b;
	a = a ^ b;//这里的代码也可以写成 a=a^b^b  b=a^a^b

	printf("a = %d b = %d\n", a, b);//结果是a=20，b=10
	return 0;
}
//异或操作符交换两个变量的缺点：
//1.可读性太差
//2.效率也不如使用临时变量的方法
//3.异或只能针对整数操作

//方法二：
int main()
{
	int a = 3;
	int b = 5;
	a = a + b;
	b = a - b;
	a = a - b;
	printf("a = %d\n", a);
	printf("b = %d\n", b);
	return 0;
}

//异或操作符：
// 1. a^a=0
// 2. 0^a=a
// 3. 异或支持交换律，例如：3^5^3和3^3^5结果都是5


int main()
{
	//4.赋值操作符：
//赋值操作符使用如下：
 int weight = 120;//体重
 double salary = 10000.0;
 salary = 20000.0;//使用赋值操作符赋值。
 // 赋值操作符可以连续使用，比如：
 int a = 10;
 int x = 0;
 int y = 20;

 //连续赋值：
 a = x = y + 1;
 //连续赋值用一下代码看着更好
 x = y + 1;
 a = x;
// 这样的写法是不是更加清晰爽朗而且易于调试。

	//复合赋值符：
	// +=
	// -=
	// *=
	// /=
	// %=
	// >>=
	// <<=
	// &=
	// |=
	// ^=

	//代码示例：
	int a = 10;
	a += 5; //也就是a = a+ 5

	int b = 5;
	a ^= 1; //也就是a = a ^ 1
	return 0;
}

int main()
{
	//5.单目操作符：只有一个操作数
	//  !        逻辑反操作
	//	-        负值
	//	+        正值
	//	&        取地址
	//	sizeof   操作数的类型长度（以字节为单位）
	//	~        对一个数的二进制按位取反
	//	--       前置、后置--
	//	++       前置、后置++
	//	*        间接访问操作符(解引用操作符)
	//(类型)     强制类型转换

	//取地址操作符和间接访问操作符一般一起使用
	//例如：
	//1.变量取地址和解引用
	int a = 10;
	printf("%p\n", &a);
	int* pa = &a;
	printf("%d", *pa);//对pa进行解引用


	//2.数组取地址
	char arr[10] = { 0 };
	char* p2 = arr;
	char* p3 = arr[0];
	
	//3.字符变量取地址
	char ch = 'w';
	char* pc = &ch;

	//	sizeof：计算操作数的类型长度（以字节为单位）
	int a = 10;
	printf("%d\n", sizeof(a));
	printf("%d\n", sizeof a);//这种情况可以省略a的括号
	//函数调用的时候不管传不传参后面都要写一个括号
	//而sizeof后面可以不写括号，说明sizeof不是函数
	printf("%d\n", sizeof(int));//int的括号不能省略
	
	//sizeof计算数组长度
	int arr[10] = { 0 };
	printf("%d\n", sizeof(arr));
	printf("%d\n", sizeof arr);
	printf("%d\n", sizeof(int[10]));

	//sizeof在计算时，sizeof内部的表达式是不计算的！！！
	int a = 10;
	short s = 5;
	printf("%d\n", sizeof(s = a + 3));//最终只计算s的大小，s只占两个字节
	printf("%d\n", s);//此处的结果为2 5 
	
	//	~  ：对一个数的二进制按位取反(包括符号位），针对的是整数的补码
	int a = 0;
	printf("%d\n", ~a);//结果是 -1

	int a = 9;
	//进行操作，把a的二进制位中的第五位改成1
	a |= (1 << 4);
	printf("%d\n", a);
	//进行操作，把a的第五位从1变回0
	a &= (~(1 << 4));
	printf("%d\n", a);

	return 0;
}

//布尔类型：
//布尔类型就是用来表示真假的
//布尔类型的使用：
#include<stdbool.h>//布尔类型的头文件
int main()
{
	//布尔类型有两个值，一个true，一个false
	_Bool flag = true;//表示真
	//也可以这样定义：
	bool a = true;
	if (flag)
	{
		printf("I Love You\n");//打印
	}
	_Bool flag = false;//表示假
	if (flag)
	{
		printf("I hate You\n");//不打印
	}
	return 0;
}

//无符号unsigned和符号signed
int main()
{
	int a = -10;
	unsigned int a = 10;//表示a没有符号，说明a只能表示正数
	//也就是说unsigned不会把最高位当作符号位来看待
	//signed会把最高位当作符号位来看待
	unsigned int d = -10;
	printf("%u\n", d);//对于一个无符号数，要使用%u来打印
	return 0;
}






